package com.m3958.firstgwt.server.servlet;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.app.Velocity;

import redis.clients.jedis.Jedis;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.m3958.firstgwt.server.model.WebHost;
import com.m3958.firstgwt.server.model.WebSite;
import com.m3958.firstgwt.server.service.AppUtilService;
import com.m3958.firstgwt.server.service.FourOFourService;
import com.m3958.firstgwt.server.service.JedisPoolService;
import com.m3958.firstgwt.server.service.RequestScopeObjectService;
import com.m3958.firstgwt.server.service.VelocityService;
import com.m3958.firstgwt.server.service.WebCacher;
import com.m3958.firstgwt.server.service.WebFrontUrlParser;
import com.m3958.firstgwt.server.types.CharactSetName;
import com.m3958.firstgwt.server.utils.ServerSideStringUtils;

import freemarker.template.Template;
import freemarker.template.TemplateException;


@Singleton
public class WebFrontServlet extends HttpServlet{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public static enum TplProcessResultFlag{
		TPL_NOT_FOUND,TPL_ERROR,SUCCESS
	}
	
	public static class TplProcessResult{
		private String result;
		private TplProcessResultFlag flag;
		
		public TplProcessResult(String result,TplProcessResultFlag flag) {
			super();
			this.setFlag(flag);
			this.result = result;
		}
		
		public int getContentLength() throws UnsupportedEncodingException{
			return result.getBytes("UTF8").length;
		}
		
		public void setResult(String result) {
			this.result = result;
		}
		public String getResult() {
			return result;
		}

		public void setFlag(TplProcessResultFlag flag) {
			this.flag = flag;
		}

		public TplProcessResultFlag getFlag() {
			return flag;
		}
	}
	
	@Inject
	private Injector injector;
	
	@Inject
	private AppUtilService autils;
	
	@Inject
	protected com.google.inject.Provider<EntityManager> emp;
	
	@Inject
	private JedisPoolService jpservice;
	
	@Inject
	private VelocityService velocityService;
	
	@Inject
	private WebCacher webCacher;
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		WebFrontUrlParser wfup = null;
		try {
			wfup = injector.getInstance(WebFrontUrlParser.class);
		} catch (Exception e1) {
			e1.printStackTrace();
			return;
		}
		
		RequestScopeObjectService rso = injector.getInstance(RequestScopeObjectService.class);
		WebSite ws = rso.getRequestWebSite();
		WebHost wh = rso.getRequestWebHost();
		if(ws == null || wh == null){
			return;
		}
		
		try {
			if(!wh.isAudit()){
				res.setContentType("text/html; charset=UTF-8");   
				res.setCharacterEncoding("UTF-8");
				Writer w = res.getWriter();
				w.write("此域名尚未经管理员审核，请联系管理员。奉化市诗篇网络科技有限公司，jianglibo@gmail.com");
				w.close();
			}
			
			if(ws.isStop()){
				res.setContentType("text/html; charset=UTF-8");   
				res.setCharacterEncoding("UTF-8");
				Writer w = res.getWriter();
				if(wfup.getMaintenceFile() != null ){
					Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(wfup.getMaintenceFile()),CharactSetName.UTF_8));
			        int numRead=0;
			        char[] buf = new char[1024];
			        while((numRead=reader.read(buf)) != -1){
			        	w.write(buf, 0, numRead);
			        }
			        reader.close();
			        w.close();
			        return;
				}
				w.write("网站维护中.......，请稍候再来访问！");
				w.close();
				return;
			}
			
			if(ws.isOutOfService()){
				;
			}
			
			
			//已經在staticFileServlet裡面處理
//			File f = wfup.getNoneFtlFile();
//			if(f != null && f.isFile()){
//				autils.sendSiteFile(req, res, f, getServletContext().getMimeType(f.getAbsolutePath()));
//			    return;
//			}
		} catch (Exception e1) {
			res.setContentType("text/html; charset=UTF-8");   
			res.setCharacterEncoding("UTF-8");
			Writer w = res.getWriter();
			w.write("该域名没有对应的网站！");
			w.close();
			return;
		}
		
		String content = null;
		TplProcessResult tpr = process(wfup);
		
		switch (tpr.flag) {
		case TPL_NOT_FOUND:
			injector.getInstance(FourOFourService.class).send404();
			return;
		case TPL_ERROR:
			autils.writeHtmlResponse(res, tpr.getResult());
		case SUCCESS:
			content = tpr.getResult();
		default:
			break;
		}
		
		if(content == null || content.isEmpty()){
			res.setStatus(HttpServletResponse.SC_NO_CONTENT);
			return;
		}
		
		content = filterContent(content);

		res.setContentType("text/html; charset=UTF-8");   
		res.setCharacterEncoding("UTF-8");
//		String etag = UUID.randomUUID().toString();
		PrintWriter writer = res.getWriter();
//		res.setHeader("Etag", etag);
		writer.write(content);
		writer.close();
		if(ws.isCacheEnable()){
			Map<String, String> paras = req.getParameterMap();
//			hostname,remoteip
			String[] ppp = new String[paras.size()];
			int i = 0;
			for(String key:paras.keySet()){
				if("hostname".equals(key) || "remoteip".equals(key)){
					ppp[i] = "";
				}else{
					ppp[i] = req.getParameter(key);
				}
				i++;
			}
			String ouri = (String) req.getAttribute("origin_ruri");
			webCacher.setItem(ws.getId(), content, ouri, ppp);
//			saveCacheCopy(req,wfup,rso,content,etag);
		}
			
	}

	private TplProcessResult process(WebFrontUrlParser wfup) throws IOException {
		WebSite ws = wfup.getWebSite();
		if("ftl".equals(ws.getTplTech())){
			return processFreeMarker(wfup);
		}else if("vm".equals(ws.getTplTech())){
			return processVelocity(wfup);
		}
		return new TplProcessResult("", TplProcessResultFlag.TPL_NOT_FOUND);
	}

	private TplProcessResult processVelocity(WebFrontUrlParser wfup) {
		String vmt = wfup.getTplPathRelativeToSiteRoot();
		if(!velocityService.templateExists(vmt)){
			return new TplProcessResult("",TplProcessResultFlag.TPL_NOT_FOUND);
		}
		
		StringWriter sWriter = new StringWriter();
		Velocity.mergeTemplate(vmt,"utf-8", wfup.getVelocityContext(), sWriter );

		return new TplProcessResult(sWriter.toString(), TplProcessResultFlag.SUCCESS);
	}

	private TplProcessResult processFreeMarker(WebFrontUrlParser wfup) throws IOException {
		Template template = null;
		try {
			template = wfup.getTpl();
		} catch (FileNotFoundException e1) {}
		
		if(template == null){
			return new TplProcessResult("",TplProcessResultFlag.TPL_NOT_FOUND);
		}
		
		StringWriter sWriter = new StringWriter();
		try {
			Map<String, Object> rm = wfup.getRootModel();
			template.process(rm, sWriter);
		} catch (TemplateException e) {
			e.printStackTrace(new PrintWriter(sWriter));
			return new TplProcessResult(sWriter.toString(),TplProcessResultFlag.TPL_ERROR);
		}
		return new TplProcessResult(sWriter.toString(), TplProcessResultFlag.SUCCESS);
	}

	private String filterContent(String content) {
		return content;
	}

	
	private void saveCacheCopy(HttpServletRequest req,WebFrontUrlParser wfup,RequestScopeObjectService rso,String content,String etag){
		Jedis jd = jpservice.getInstance();
		if(jd != null){
			try {
				String ouri = (String) req.getAttribute("origin_ruri");
				String rurl = ServerSideStringUtils.getCacheString(ouri,req.getQueryString());
				int siteId = rso.getRequestWebSite().getId();
				String oldEtag = req.getHeader("If-None-Match");
				Map<String, String> urlCacheMap = new HashMap<String, String>();
				urlCacheMap.put("etag", etag);
				urlCacheMap.put("content", content);
				jd.hmset(rurl, urlCacheMap);
				jd.set(etag, rurl);
				if(oldEtag != null)jd.del(oldEtag);
				String ob2etag = rso.getRequestWebSite().getId() + "," +  wfup.getObName() + "," + wfup.getObid();
				//(siteId)7878,article,72828
				jd.set(ob2etag,etag);
				
				jd.rpush("site:" + siteId, etag);//这里包含了所有的cache条目。
				jd.rpush("site:" + siteId, ob2etag);
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				jpservice.putBack(jd);
			}
		}
	}
}
